//
//  TableVM.swift
//  CooperSwift_Example
//
//  Created by 计海峰 on 2021/5/24.
//  Copyright © 2021 CocoaPods. All rights reserved.
//

import Foundation
import RxDataSources
import RxSwift

private struct AssociateKeys {
    static var sectionKey: Void?
    static var sectionSubjectKey: Void?
    static var serviceSubjectKey: Void?
    static var targetBlockKey: Void?
    static var serviceBlockKey: Void?
    static var dataSourceKey: Void?
    static var isRefreshingKey: Void?
    static var reloadSubjectKey: Void?
}

// MARK: - view model 默认方法 <genCellDone, configDataSource>
public protocol TableViewModelProtocol: ViewModelProtocol {
    
    // 便携写法 可以直接 使用dataSource 的
    func genCellDone(item: TableCellConfigProtocol, indexPath: IndexPath, cell: UITableViewCell, table: UITableView)
    
    // 配置 datasource
    @discardableResult
    func configDataSource() -> RxTableViewSectionedReloadDataSource<SectionM>
}

public extension TableViewModelProtocol {
    /// 便携写法 可以直接 使用dataSource 的
    func genCellDone(item: TableCellConfigProtocol, indexPath: IndexPath, cell: UITableViewCell, table: UITableView) {
        
    }
}

// MARK: - view model 默认方法 <initDown, configDown, refresh, pullUp, item>
public extension TableViewModelProtocol {
    
    /// 配置结束 开始方法
    func initDown() {
        print("table initDown")
    }
    
    /// 配置结束 开始方法
    func configDown() {
        print("table configDown")
    }
    
    /// 下拉刷新
    func refresh() {
        print("table refresh")
    }
    
    /// 上拉加载更多
    func pullUp()  {
        print("table pullUp")
    }
    
    ///
    func item(indexPath: IndexPath) -> TableCellConfigProtocol? {
        return self.sections[safe: indexPath.section]?.items[safe: indexPath.row]
    }
 
}

// MARK: - table cell 高度  不会、不会、不会、不会  主动调用
/// tableview的高度 不会主动调用
/// 需要vm 继承 NSObject & UITableViewDelegate TableViewModelProtocol  然后主动实现tableView heightForRowAt indexPath 方法
/// 之后调用改方法
public extension TableViewModelProtocol where Self: UITableViewDelegate {
    func vm_tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if let item = self.sections[safe: indexPath.section]?.items[safe: indexPath.row] {
            if item.cellHeight !=  UITableView.automaticDimension {
                debugPrint(" ⭐️⭐️⭐️ item control cell height --> \(item.cellHeight)")
                return item.cellHeight > 0 ? item.cellHeight : 0.001
            }
        }
        return UITableView.automaticDimension
    }
}


// MARK: - sections
public extension TableViewModelProtocol {
    
    typealias SectionM = SectionModel<Any, TableCellConfigProtocol>
  
    // MARK: -  table 对应 sections BehaviorSubject
    var sectionsSubject: BehaviorSubject<[SectionM]> {
        get {
            return associatedObject(forKey: &AssociateKeys.sectionSubjectKey, default: BehaviorSubject<[SectionM]>(value: self.sections), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.sectionSubjectKey, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
  
    // MARK: -  table 对应 sections
    var sections: [SectionM]
    {
        get {
            return associatedObject(forKey: &AssociateKeys.sectionKey, default: [SectionM](), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.sectionKey, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            self.sectionsSubject.onNext(newValue)
        }
    }

   // MARK: -  第一个section 没有的话 默认创建
   @discardableResult
   func firstSection() -> SectionM {
    if let section = self.sections.first {
           return section
       }
    self.sections += [SectionModel<Any, TableCellConfigProtocol>(model: "Section0", items: [])]
    return self.sections.first!
   }
    
    /// 更新cell到第一个section 会删除之前的
    /// - Parameter items: cell 对应的 数据配置 数组
    func updateFirstSectionItems(_ items: [TableCellConfigProtocol]) {
        var sectionOne = firstSection()
        sectionOne.items = items
        self.sections[0] = sectionOne
    }
    
    /// 添加cell 到相第一个 section
    /// - Parameter items: cell 对应的 数据配置 数组
    func addFirstSectionItems(_ items: [TableCellConfigProtocol]) {
        var sectionOne = firstSection()
        sectionOne.items += items
        self.sections[0] = sectionOne
    }
    
}


// MARK: - rx data source
public extension TableViewModelProtocol {
    
    // MARK: - dataSource 初始化
    private var dataSource : RxTableViewSectionedReloadDataSource<SectionM>? {
        get {
            return objc_getAssociatedObject(self, &AssociateKeys.dataSourceKey) as? RxTableViewSectionedReloadDataSource<SectionM>
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.dataSourceKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    // MARK: - RxTableViewSectionedReloadDataSource
    @discardableResult
    func configDataSource() -> RxTableViewSectionedReloadDataSource<SectionM> {
        if let ds = dataSource {
            return ds
        }
        dataSource = RxTableViewSectionedReloadDataSource<SectionM>(
            configureCell: { dataSource, tv, indexPath, item in
                
                let cell = tv.dequeueReusableCell(indexPath: indexPath, cls: item.cellCls())
                
                // 绑定数据
                cell.bindTo(item)
                
                // cell 默认配置
                cell.selectionStyle = .none
                // 背景色
                if let bgColor = item.bgColor {
                    cell.backgroundColor = bgColor
                }
                // 行高
                cell.isHidden = item.cellHeight == 0
                
                // 绑定的数据给个 datasource cell 回调
                self.genCellDone(item: item, indexPath: indexPath, cell: cell, table: tv)
                
                return cell
            },
            canEditRowAtIndexPath: { _, _ in false },
            canMoveRowAtIndexPath: { _, _ in false }
        )
        return dataSource!
    }
    
}


// MARK: - service
public extension TableViewModelProtocol {
    
    typealias TargetBlock = (_ service: TableViewModelFromTargetServiceEnum) -> Any?
    
    // MARK: -  table 对应 sections BehaviorSubject
    var serviceSubject: BehaviorSubject<Any> {
        get {
            return associatedObject(forKey: &AssociateKeys.serviceSubjectKey, default: BehaviorSubject(value: ""), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.serviceSubjectKey, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var serviceBlock: TargetBlock? {
        get {
            return (objc_getAssociatedObject(self, &AssociateKeys.serviceBlockKey) as? Self.TargetBlock)
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.serviceBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
      
    
    // MARK: - 配置服务
    func configServicBlock(bag: DisposeBag, block: @escaping TargetBlock) -> Void {
        serviceBlock = block
    }
    
    // MARK: - 发出服务
    /// 获取当前table
    func currentTV() -> UITableView? {
        guard let block = serviceBlock else { return nil }
        return block(.table) as? UITableView
    }
    
    /// 获取当前vc
    func currentVC() -> UIViewController? {
        guard let block = serviceBlock else { return nil }
        return block(.controller) as? UIViewController
    }
    
    /// 获取当前view
    func currentV() -> UIView? {
        guard let block = serviceBlock else { return nil }
        return block(.view) as? UIView
    }
    
    /// 获取当前vc view table
    func currentAll() -> (UIViewController, UIView, UITableView)? {
        guard let block = serviceBlock else { return nil }
        return (block(.all) as? (UIViewController, UIView, UITableView))
    }
    
    /// 刷新table
    func reloadTable() {
        let val = try! reloadSubject.value() + 1
        reloadSubject.onNext(val)
    }
    
    /// 结束编辑
    func endEdit() {
        guard let block = serviceBlock else { return }
        let _ = block(.endEdit)
    }
    
}

// MARK: - other
public extension TableViewModelProtocol {
    
    /// 是否刷新中...
    var isRefreshing: Bool {
        get {
            return objc_getAssociatedObject(self, &AssociateKeys.isRefreshingKey) as? Bool ?? false
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.isRefreshingKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
    
    /// 刷新节流
    var reloadSubject: BehaviorSubject<Int> {
        get {
            return associatedObject(forKey: &AssociateKeys.reloadSubjectKey, default: BehaviorSubject<Int>(value: 0), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.reloadSubjectKey, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
}

// MARK: - 加载状态
public enum PageLoadingState {
    case loading, normal, noData, failure, success, loadingGif
    func config() -> EmptyDataSetConfigure {
        switch self {
        case .loading:
            return EmptyConfig.loading
        case .loadingGif:
            return EmptyConfig.loadingGif
        case .noData:
            return EmptyConfig.noData
        case .failure:
            return EmptyConfig.failure
        case .success:
            return EmptyConfig.success
        default:
            return EmptyConfig.normal
        }
    }
}

public extension TableViewModelProtocol where Self : RefreshControllable  {
    func toState(_ state: PageLoadingState) -> Void {
        if self.serviceBlock != nil {
            guard let tv = self.serviceBlock!(.table) as? UITableView else {
                return
            }
            self.rx.updateEmptyDataSet(tv, config: state.config())
        }
    }
}
